#ifndef __MONITOR_HPP__
#define __MONITOR_HPP__

#include <mutex>
#include <functional>
#include <iostream>
#include <memory>

/* 
An implementation of the sharing mutex pointer
 */
template <class T>
class Monitor
{
public:
    Monitor(const Monitor&) = default;
    Monitor(const Monitor&&) = delete;
    Monitor(Monitor&) = default;
    Monitor(Monitor&&) = default;

    template <typename... ARGS>
    Monitor(ARGS &&...args) : _t(std::make_shared<T>(std::forward<ARGS>(args)...)), _mutex(std::make_shared<std::mutex>()) {};

    struct MonitorHelper
    {
        MonitorHelper(Monitor *mon) : _mon(mon), _lock(*(mon->_mutex)) {}
        std::shared_ptr<T> operator->() { return _mon->_t; }

        Monitor *_mon;
        std::unique_lock<std::mutex> _lock;
    };

    MonitorHelper operator->() { return MonitorHelper(this); }
    MonitorHelper get_access() { return MonitorHelper(this); }
    std::shared_ptr<T> unsafe_get_access() { return _t; }

private:
    std::shared_ptr<std::mutex> _mutex;
    std::shared_ptr<T> _t;
};

#endif
